#ifndef PW_PBL_COROUTINE_LISTEXECUTOR_HPP
#define PW_PBL_COROUTINE_LISTEXECUTOR_HPP

#include <coroutine>
#include <concepts>
#include <utility>
#include "IAwaitable.hpp"

/// 协程名字空间
/// @note 本库的协程使用类似Javascript的单线程模型，多线程使用时各线程均可开启自己的协程执行器，
/// 但各线程的协程之间通信时需要另加同步机制，尤其注意co_await另一个线程的协程或等待器并不安全
namespace pw_pbl::co
{
	/// 协程默认执行器类
	struct ListExecutor
	{
		struct IAwaitable;

		struct SAwaitHead
		{
			IAwaitable *pNext = nullptr;
		};

		struct SAwaitNode : public SAwaitHead
		{
			SAwaitHead *pPrev = nullptr;

			inline void remove_from_queue(void)
			{
				if (pPrev)
					pPrev->pNext = pNext;
				if (pNext)
				{
					pNext->pPrev = pPrev;
					pNext = nullptr;
				}
				pPrev = nullptr;
			}

			SAwaitNode(void) = default;
			SAwaitNode(const SAwaitNode &) = delete;
			SAwaitNode(SAwaitNode &&old) : SAwaitHead(old), pPrev(old.pPrev)
			{
				if (pPrev)
				{
					pPrev->pNext = (IAwaitable *)this;
					old.pPrev = nullptr;
				}
				if (pNext)
				{
					pNext->pPrev = this;
					old.pNext = nullptr;
				}
			}
			~SAwaitNode(void) { remove_from_queue(); }

			SAwaitNode &operator=(const SAwaitNode &) = delete;
			SAwaitNode &operator=(SAwaitNode &&old) = delete;
		};

		struct IAwaitable : public SAwaitNode, public co::IAwaitable<IAwaitable>
		{
			inline void join_after(SAwaitHead *head)
			{
				pPrev = head;
				head->pNext = this;
			}
		};

		SAwaitHead head;
		SAwaitHead *pTail = &head;

		void await_suspend(IAwaitable &fr)
		{
			fr.join_after(pTail);
			pTail = &fr;
		}

		/// 运行协程队列
		/// @return 队列是否已空
		bool run(void) &
		{
			if (!head.pNext)
				return true;
			SAwaitHead newHead;
			SAwaitHead *pLastUnready = &head; // 跟踪当前执行队列的动态队尾——最后一个仍需等待执行的项
			pTail = &newHead;				  // 当前循环新添加的项放到临时队列中以免刚加入队列又立即执行
			for (IAwaitable *pCur = pLastUnready->pNext; pCur; pCur = pLastUnready->pNext)
			{
				if (pCur->virtual_ready())
				{
					pCur->remove_from_queue();
					pCur->virtual_resume();
				}
				else
					pLastUnready = pCur;
			}
			if (newHead.pNext)
				newHead.pNext->join_after(pLastUnready); // 新添加项的队列合并到原队列尾部
			else
				pTail = pLastUnready;

			return !head.pNext;
		}

		inline auto next(void)
		{
			return [pre = 0]() mutable { return pre++; };
		}

		ListExecutor() = default;

	private:
		ListExecutor(const ListExecutor &) = delete;
		ListExecutor(ListExecutor &&) = delete;
		ListExecutor &operator=(const ListExecutor &) = delete;
		ListExecutor &operator=(ListExecutor &&) = delete;
	};
} // namespace pw_pbl::co

#endif // PW_PBL_COROUTINE_LISTEXECUTOR_HPP
